package com.pansoft.nfc.acs;

import com.efounder.chat.utils.AESSecretUtil;
import com.pansoft.nfc.mifare.Common;

import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.pansoft.nfc.NfcCommonUtils.getBlockByPosition;
import static com.pansoft.nfc.NfcCommonUtils.getSectorByPosition;
import static com.pansoft.nfc.acs.AcsBleManager.APDU_COMMAND_AUTH_PREFIX;
import static com.pansoft.nfc.acs.AcsBleManager.APDU_COMMAND_AUTH_SUFFIX;
import static com.pansoft.nfc.acs.AcsBleManager.APDU_COMMAND_READ_PREFIX;
import static com.pansoft.nfc.acs.AcsBleManager.APDU_COMMAND_READ_SUFFIX;
import static com.pansoft.nfc.acs.AcsBleManager.APDU_COMMAND_WRITE_PREFIX;

/**
 * Acs蓝牙读卡器，读写卡执行的命令
 * @author wang
 */
public class ApduListManager {

    /**
     * 组织读卡的命令
     * @return 命令数组
     */
    public static List<String> getReadApduList(String[] positions) {

        //数组的index
        int j = 0;
        List<String> readApduList = new ArrayList<>();
        String[] strings = new String[positions.length];
        for (int i = 0; i < positions.length; i++) {
            //根据位置确定要读取的sector
            int sector = getSectorByPosition(Integer.valueOf(positions[i]));
            //一次读取5个扇区
            if (sector <= 27) {
                int firstBlockNo = getBlockByPosition(Integer.valueOf(positions[i]));
                //区块号
                for (int k = firstBlockNo; k < firstBlockNo + 20; k++) {
                    //每4个区块号，到秘钥区块号，跳过
                    if ((k + 1) % 4 == 0) {
                        continue;
                    }
                    //区块号
                    String blockNo = Integer.toHexString(k);
                    if (blockNo.length() < 2) {
                        blockNo = "0" + blockNo;
                    }
                    //每扇区开始的时候验证
                    if (k % 4 == 0) {
                        readApduList.add(j, APDU_COMMAND_AUTH_PREFIX + blockNo
                                + APDU_COMMAND_AUTH_SUFFIX);
                        j++;
                    }
                    // 前缀 + 块号 + 后缀 每次读的字数
                    readApduList.add(j, APDU_COMMAND_READ_PREFIX + blockNo
                            + APDU_COMMAND_READ_SUFFIX);
                    j++;
                }
            } else {
                //一次读一个扇区
                int firstBlockNo = getBlockByPosition(Integer.valueOf(positions[i]));
                String firstblockNo = Integer.toHexString(firstBlockNo);
                if (firstblockNo.length() < 2) {
                    firstblockNo = "0" + firstblockNo;
                }
                readApduList.add(j, APDU_COMMAND_AUTH_PREFIX + firstblockNo
                        + APDU_COMMAND_AUTH_SUFFIX);
                j++;
                //区块号
                for (int k = firstBlockNo; k < firstBlockNo + 15; k++) {
                    //区块号
                    String blockNo = Integer.toHexString(k);
                    if (blockNo.length() < 2) {
                        blockNo = "0" + blockNo;
                    }
                    // 前缀 + 块号 + 后缀 每次读的字数
                    readApduList.add(j, APDU_COMMAND_READ_PREFIX + blockNo
                            + APDU_COMMAND_READ_SUFFIX);
                    j++;
                }
            }
        }


        return readApduList;
    }

    /**
     * 读取私钥的apdu命令
     * @param position
     * @return
     */
    public static List<String> getReadPriKeyList(int position) {

        //数组的index
        int j = 0;
        List<String> readApduList = new ArrayList<>();
        int sector = getSectorByPosition(position);
        //一次读取5个扇区
        if (sector <= 32) {
            int firstBlockNo = getBlockByPosition(position);
            //区块号
            for (int k = firstBlockNo; k < firstBlockNo + 20; k++) {
                //每4个区块号，到秘钥区块号，跳过
                if ((k + 1) % 4 == 0) {
                    continue;
                }
                //区块号
                String blockNo = Integer.toHexString(k);
                if (blockNo.length() < 2) {
                    blockNo = "0" + blockNo;
                }
                //每扇区开始的时候验证
                if (k % 4 == 0) {
                    readApduList.add(j, APDU_COMMAND_AUTH_PREFIX + blockNo
                            + APDU_COMMAND_AUTH_SUFFIX);
                    j++;
                }
                // 前缀 + 块号 + 后缀 每次读的字数
                readApduList.add(j, APDU_COMMAND_READ_PREFIX + blockNo
                        + APDU_COMMAND_READ_SUFFIX);
                j++;
            }
        } else {
            //一次读一个扇区
            int firstBlockNo = getBlockByPosition(position);
            String firstblockNo = Integer.toHexString(firstBlockNo);
            if (firstblockNo.length() < 2) {
                firstblockNo = "0" + firstblockNo;
            }
            readApduList.add(j, APDU_COMMAND_AUTH_PREFIX + firstblockNo
                    + APDU_COMMAND_AUTH_SUFFIX);
            j++;
            //区块号
            for (int k = firstBlockNo; k < firstBlockNo + 15; k++) {
                //区块号
                String blockNo = Integer.toHexString(k);
                if (blockNo.length() < 2) {
                    blockNo = "0" + blockNo;
                }
                // 前缀 + 块号 + 后缀 每次读的字数
                readApduList.add(j, APDU_COMMAND_READ_PREFIX + blockNo
                        + APDU_COMMAND_READ_SUFFIX);
                j++;
            }
        }


        return readApduList;
    }

    /**
     * 组织钱包数据，这里需要返回十六进制
     * 每个字段前加两个字节，用来标识这个字段的长度，便于寻址读写
     *
     * @param chainId    链编号
     * @param address    地址
     * @param privateKey 私钥，btc是助记词
     * @return 十六进制字符串
     */
    public static String parseWalletData(String chainId, String address, String privateKey) {
        String hexChainId = Utils.toHexString(chainId.getBytes()).replace((" "), "").replace("\n", "");
        System.out.println(hexChainId);
        System.out.println(hexChainId.length());
        String preChainId = Integer.toHexString(hexChainId.length());
        preChainId = handlePreLength(preChainId);
        System.out.println(preChainId);
        String hexAddress = Utils.toHexString(address.getBytes()).replace((" "), "").replace("\n", "");
        System.out.println(hexAddress);
        String preAddress = Integer.toHexString(hexAddress.length());
        preAddress = handlePreLength(preAddress);
        System.out.println(preAddress);
        AESSecretUtil aesSecretUtil = new AESSecretUtil(Common.NFC_WALLET_SECRET_KEY);
        String encryptPrivateKey = aesSecretUtil.encrypt(privateKey);
        String hexPrivateKey = Utils.toHexString(encryptPrivateKey.getBytes()).replace((" "), "").replace("\n", "");
        System.out.println(hexPrivateKey);
        String prePrivateKey = Integer.toHexString(hexPrivateKey.length());
        prePrivateKey = handlePreLength(prePrivateKey);
        System.out.println(prePrivateKey);
        String hexString = preChainId + hexChainId + preAddress + hexAddress + prePrivateKey + hexPrivateKey;
//        int blockSize = hexString.length() / 32 + 1;
        //每10个区块存储一个钱包
        int blockSize = 15;
        //不足这些扇区的数据，补00h
        while (hexString.length() < blockSize * 16 * 2) {
            hexString = hexString.concat("0");
        }
        return hexString;
    }

    public static void main(String[] args) {
        System.out.println(parseWalletData("1", "1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm",
                "acoustic acoustic acoustic acoustic acoustic acoustic acoustic acoustic acoustic acoustic acoustic acoustic"));
    }

    /**
     * 用两个字节的十六进制表示字段长度
     * 如果不足两位，前面补0
     *
     * @param preLength
     */
    private static String handlePreLength(String preLength) {
        if (preLength.length() < 2) {
            preLength = "0" + preLength;
        }
        return preLength.replace((" "), "").replace("\n", "");
    }

    /**
     * 拼接写入1扇区的数据
     *
     * @param pos 钱包位置
     * @param ver 数据版本号
     * @return String 十六进制
     */
    public static String parseStartData(String pos, String ver) {
        Map<String, String> jsonMap = new HashMap<>();
        jsonMap.put("p", pos);
        jsonMap.put("v", ver);
        JSONObject jsonObject = new JSONObject(jsonMap);
        String startString = Common.byte2HexString(jsonObject.toString().getBytes());
        while (startString.length() < 3 * 16 * 2) {
            startString = startString.concat("0");
        }
        return startString;
    }

    public static String parseStartData(String jsonString) {
        String startString = Common.byte2HexString(jsonString.getBytes());
        while (startString.length() < 3 * 16 * 2) {
            startString = startString.concat("0");
        }
        return startString;
    }

    /**
     * 写入的钱包数据
     *
     * @param chainId    id
     * @param address    address
     * @param privateKey privateKey
     * @return list
     */
    public static List<String> getWriteWalletList(String chainId, String address, String privateKey) {
        //得到的是十六进制String
        String string = parseWalletData(chainId, address, privateKey);
        //写入钱包数据，从blcok 8开始， 一直写到结尾
        return getWriteHexList(string, 8, 14);
    }

    /**
     * 读取第0扇区数据uid
     * 第1扇区数据PIN
     * 第2扇区数据 卡片存储的钱包信息 cardInfo {"v":"3","p","0,1"}
     */
    public static List<String> getUidPinSectorList() {
        List<String> hexList = new ArrayList<>();
        //验证
        hexList.add(0, APDU_COMMAND_AUTH_PREFIX + "00"
                + APDU_COMMAND_AUTH_SUFFIX);
        //读取三次
        for (int i = 0; i < 3; i++) {
            String blockNo1 = Integer.toHexString(i);
            if (blockNo1.length() < 2) {
                blockNo1 = "0" + blockNo1;
            }
            hexList.add(i + 1, APDU_COMMAND_READ_PREFIX + blockNo1
                    + APDU_COMMAND_READ_SUFFIX);
        }

        //验证
        hexList.add(4, APDU_COMMAND_AUTH_PREFIX + "04"
                + APDU_COMMAND_AUTH_SUFFIX);
        //读取三次
        for (int i = 4; i < 7; i++) {
            String blockNo1 = Integer.toHexString(i);
            if (blockNo1.length() < 2) {
                blockNo1 = "0" + blockNo1;
            }
            System.out.println(blockNo1);
            hexList.add(i + 1, APDU_COMMAND_READ_PREFIX + blockNo1
                    + APDU_COMMAND_READ_SUFFIX);
        }

        //验证
        hexList.add(8, APDU_COMMAND_AUTH_PREFIX + "08"
                + APDU_COMMAND_AUTH_SUFFIX);
        //读取三次
        for (int i = 8; i < 11; i++) {
            String blockNo1 = Integer.toHexString(i);
            if (blockNo1.length() < 2) {
                blockNo1 = "0" + blockNo1;
            }
            System.out.println(blockNo1);
            hexList.add(i + 1, APDU_COMMAND_READ_PREFIX + blockNo1
                    + APDU_COMMAND_READ_SUFFIX);
        }

        return hexList;
    }

    /**
     * 写入一个扇区的数据
     */

    /**
     * 处理输入的数据
     *
     * @param blockSize  写入的扇区的大小，一个扇区3条数据
     * @param startBlock 开始写入的扇区号
     * @return List
     */
    public static List<String> getWriteHexList(String string, int startBlock, int blockSize) {

        List<String> hexList = new ArrayList<>();
        //数据编号
        int j = 0;
        //区块编号,第一次是2扇区第一块04h号
        int k = startBlock;
        //正则，每16 * 2个分割
//        String[] stringArray = hexString.split("(?<=\\G................................)", 0);

        List<String> hexStringList = new ArrayList<>();
        for (int i = 0; i < blockSize; i++) {
            hexStringList.add(string.substring(i * 32, (i + 1) * 32));
        }

        for (int i = 0; i < hexStringList.size(); i++) {

            if (startBlock < 128) {
                //每4个为秘钥区块，区块号+1, 验证，继续读写下一个扇区
                if (i % 3 == 0 && i > 0) {
                    k++;
                }
                //区块号
                String blockNo = Integer.toHexString(k);
                if (blockNo.length() < 2) {
                    blockNo = "0" + blockNo;
                }
                //每4个区块，验证一下，同一个扇区只需验证一次
                if (i % 3 == 0) {
                    hexList.add(j, APDU_COMMAND_AUTH_PREFIX + blockNo
                            + APDU_COMMAND_AUTH_SUFFIX);
                    j++;
                }
                hexList.add(j, APDU_COMMAND_WRITE_PREFIX + blockNo + "10"
                        + hexStringList.get(i));
//            }
                j++;
                k++;
            } else {
                //15个block一个sector，直接依次写入
                //区块号
                String blockNo = Integer.toHexString(k);
                if (blockNo.length() < 2) {
                    blockNo = "0" + blockNo;
                }
                String authBolckNo = Integer.toHexString(k + 15);
                if (authBolckNo.length() < 2) {
                    authBolckNo = "0" + authBolckNo;
                }
                if (i == 0) {
                    //只需验证一次
                    hexList.add(j, APDU_COMMAND_AUTH_PREFIX + authBolckNo
                            + APDU_COMMAND_AUTH_SUFFIX);
                    j++;
                }
                hexList.add(j, APDU_COMMAND_WRITE_PREFIX + blockNo + "10"
                        + hexStringList.get(i));
                j++;
                k++;
            }

        }
        return hexList;
    }

    public static List<String> getWriteStart(String addr, String done) {
//        Map<String, String> map = new HashMap<>();
//        map.put("addr", addr);
//        map.put("done", done);
//        JSONObject jsonObject = new JSONObject(map);
        return getWriteHexList(addr, 4, 1);
    }

    /**
     * 清空卡片，全部置0
     *
     * @return 0
     */
    public static List<String> getWriteZero() {
        //清空卡片，从block 4开始
        return getWriteHexList("", 4, 15);
    }

}
